﻿using StructuredProgrammingAssignment.App_Start;
using StructuredProgrammingAssignment.Helpers;
using StructuredProgrammingAssignment.Linq;
using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.Linq;
using System.Linq.Dynamic;

namespace StructuredProgrammingAssignment.Controllers
{
	public class ShoppingController : SPStuffController
	{
		private Object thisLock = new Object();

		/**
		 * Get list of all shopping stuffs with dynamic filter
		 **/
		[System.Web.Http.AcceptVerbs("GET", "POST")]
		public Object[] GetStuffs(
			string userId,						// current user id, used for authorization
			bool includeOwnerStuffs = false,	// true if result should contain current user's stuffs

			string where = null,				// dynamic filter clause, this feature can be turn off via config
			string order = null,				// dynamic order clause, this feature can be turn off via config

			int categoryId = int.MinValue,		// filter stuffs by category

			string name = null,					// filter by name
			bool nameExact = false,				// search for exact stuff name if true

			string description = null,			// filter by description
			bool descriptionExact = false,		// search for exact stuff description if true

			DateTime? modifiedFrom = null,		// set minimum modified datetime
			DateTime? modifiedTo = null,		// set maximum modified datetime
			DateTime? createdFrom = null,		// set minimum created datetime
			DateTime? createdTo = null,			// set maximum created datetime

			decimal priceMin = decimal.MinValue,	// set minimum price
			decimal priceMax = decimal.MaxValue,	// set maximum price
			bool priceExclusive = true,			// exclusive or not

			string orderCol = "Name",			// order column
			string orderDir = "ASC",			// order direction
			int offset = 0,						// specifies the number of rows to skip
			int limit = 0						// the number of rows to be retrieved
		) {
			try {
				SPDataContext db = new SPDataContext();

				// Authorization
				Guid parsedUserId;
				if (!Guid.TryParse(userId, out parsedUserId)) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}
				// Double check
				var account = (from a in db.UserAccounts
							   where a.Id.Equals(parsedUserId)
							   select a).FirstOrDefault();
				if (account == null) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}

				// Retrieve list of stuffs
				var stuffs = (from s in db.UserStuffs
							  select s);

				// include owner stuffs
				if (!includeOwnerStuffs) {
					stuffs = (from s in stuffs
							  where !s.UserId.Equals(parsedUserId)
							  select s);
				}

				// Return list of stuffs
				return GetStuffs(stuffs.ToList(), where, order, categoryId, name, nameExact, description, descriptionExact, modifiedFrom, modifiedTo, createdFrom, createdTo, priceMin, priceMax, priceExclusive, orderCol, orderDir, offset, limit);
			} catch (Exception e) {
				return ExceptionResult(e);
			}
		} // GetStuffs

		/**
		 * Get information about a single user stuff
		 **/
		[System.Web.Http.AcceptVerbs("GET", "POST")]
		public Object[] GetStuff(
			string userId,						// current user id, used for authorization
			int stuffId							// user stuff id
		) {
			try {
				SPDataContext db = new SPDataContext();

				// Authorization
				Guid parsedUserId;
				if (!Guid.TryParse(userId, out parsedUserId)) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}
				// Double check
				var account = (from a in db.UserAccounts
							   where a.Id.Equals(parsedUserId)
							   select a).FirstOrDefault();
				if (account == null) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}

				// Get the stuff
				UserStuff stuff = (from s in db.UserStuffs
							  where s.Id == stuffId
							  select s).FirstOrDefault();

				if (stuff == null) {
					return FailureResult("Invalid user stuff.", "invalid user stuff");
				}

				return SuccessResult(SPHelper.JsonUserStuff(stuff));
			} catch (Exception e) {
				return ExceptionResult(e);
			}
		} // GetStuff

		/**
		 * Send order for a user stuff
		 **/
		[System.Web.Http.AcceptVerbs("GET", "POST")]
		public Object[] OrderStuff(
			string userId,						// current user id, used for authorization
			int stuffId,						// user stuff id
			int paymentType,					// 0: Meet in person; 1: Transfer; 2: Postal; 3: Online

			decimal offerMoney = decimal.MinValue,	// offer price
			int status = 0,						// 0: Pending; 1: Accepted; 2: Denied
			string properties = null			// custom properties of the order
		) {
			try {
				SPDataContext db = new SPDataContext();

				// Authorization
				Guid parsedUserId;
				if (!Guid.TryParse(userId, out parsedUserId)) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}
				// Double check
				var account = (from a in db.UserAccounts
							   where a.Id.Equals(parsedUserId)
							   select a).FirstOrDefault();
				if (account == null) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}

				// Get the stuff
				UserStuff stuff = (from s in db.UserStuffs
							  where s.Id == stuffId
							  select s).FirstOrDefault();
				if (stuff == null) {
					return FailureResult("Invalid user stuff.", "invalid user stuff");
				}

				if (offerMoney == decimal.MinValue) { 
					offerMoney = stuff.UnitPrice;
				}

				Order order = new Order() {
					StuffId = stuffId,
					UserOrderId = parsedUserId,
					Status = status,
					OfferMoney = offerMoney,
					PaymentType = paymentType,
					Properties = properties
				};				

				// Submit changes
				lock (thisLock) {
					db.Orders.InsertOnSubmit(order);
					db.SubmitChanges();
					order = db.Orders.AsEnumerable().Last();
				}

				return SuccessResult(SPHelper.JsonOrder(order));
			} catch (Exception e) {
				return ExceptionResult(e);
			}
		} // OrderStuff

		/**
		 * Get list of all shopping stuffs with dynamic filter
		 **/
		[System.Web.Http.AcceptVerbs("GET", "POST")]
		public Object[] GetCategories(
			string userId
		) {
			try {
				SPDataContext db = new SPDataContext();

				// Authorization
				Guid parsedUserId;
				if (!Guid.TryParse(userId, out parsedUserId)) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}
				// Double check
				var account = (from a in db.UserAccounts
							   where a.Id.Equals(parsedUserId)
							   select a).FirstOrDefault();
				if (account == null) {
					return FailureResult("You are not authorized to execute this operation.", "authorization error");
				}

				// Retrieve list of stuffs
				var categories = (from c in db.Categories select c);

				List<Object> returnObjs = new List<Object>();
				foreach (Category category in categories) {
					returnObjs.Add(SPHelper.JsonCategory(category));
				}
				if (returnObjs.Count == 0) returnObjs = null;

				// Return list of categories
				return SuccessResult(returnObjs);
			} catch (Exception e) {
				return ExceptionResult(e);
			}
		} // GetCategories

	} // ShoppingController
}
